package sip

import (
	"fmt"
	"bytes"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"math/rand"
	"strings"
	"bufio"
	"time"
)

type Request http.Request

const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz"

func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
	u, err := url.Parse(urlStr)
	if err != nil {
		return nil, err
	}
	rc, ok := body.(io.ReadCloser)
	if !ok && body != nil {
		rc = ioutil.NopCloser(body)
	}
	req := &Request{
		Method:     method,
		URL:        u,
		Proto:      "SIP/2.0",
		ProtoMajor: 2,
		ProtoMinor: 0,
		Header:     make(http.Header),
		Body:       rc,
		Host:       u.Host,
	}
	if body != nil {
		switch v := body.(type) {
		case *strings.Reader:
			req.ContentLength = int64(v.Len())
		case *bytes.Buffer:
			req.ContentLength = int64(v.Len())
		}
	}
	
	return req, nil
}

func (req *Request)UserAgent() string {
	return ((*http.Request)(req)).UserAgent()
}

func (req *Request)Write(w io.Writer) error {
	ruri := req.URL.RequestURI()

	// TODO(bradfitz): escape at least newlines in ruri?
	if req.Method == "" {
		return nil // missing method
	}
	bw := bufio.NewWriter(w)
	fmt.Fprintf(bw, "%s %s %s\r\n", req.Method, ruri, req.Proto)

	// Use the defaultUserAgent unless the Header contains one, which
        // may be blank to not send the header.
	userAgent := "GoSipClient"
	if req.Header != nil {
		if _, ok := req.Header["User-Agent"]; !ok {
			req.Header.Add("User-Agent", userAgent)
		}
	}
	
	
	for k, v := range req.Header {
		for e := range v {
			fmt.Fprintf(bw, "%s: %s\r\n", k, v[e])
		}
	}
		
	io.WriteString(bw, "\r\n")

	return bw.Flush()
}

func GenerateCallid(uaStatic string) string {
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	b := make([]byte, 20)
	for i := range b {
		b[i] =  chars[r.Intn(len(chars))]
	}
	return string(b)+uaStatic
}